{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f0159866",
   "metadata": {},
   "source": [
    "# Autonomous Trader with an Evaluator"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fa53c8a",
   "metadata": {},
   "source": [
    "We use an evaluator agent which we created as an MCP server in this implementation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "62b83448",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "from pathlib import Path\n",
    "\n",
    "# For access to resources in the week's home directory\n",
    "project_root = Path.cwd().parent.parent\n",
    "sys.path.insert(0, str(project_root))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7145d501",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from dotenv import load_dotenv\n",
    "from agents import Agent, Runner, trace, Tool\n",
    "from agents.mcp import MCPServerStdio\n",
    "from IPython.display import Markdown, display\n",
    "from datetime import datetime\n",
    "from accounts_client import read_accounts_resource, read_strategy_resource\n",
    "from accounts import Account\n",
    "\n",
    "load_dotenv(override=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "89fb41c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "polygon_api_key = os.getenv(\"POLYGON_API_KEY\")\n",
    "polygon_plan = os.getenv(\"POLYGON_PLAN\")\n",
    "\n",
    "is_paid_polygon = polygon_plan == \"paid\"\n",
    "is_realtime_polygon = polygon_plan == \"realtime\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7beba40b",
   "metadata": {},
   "outputs": [],
   "source": [
    "if is_paid_polygon or is_realtime_polygon:\n",
    "    market_mcp = {\"command\": \"uvx\",\"args\": [\"--from\", \"git+https://github.com/polygon-io/mcp_polygon@master\", \"mcp_polygon\"], \"env\": {\"POLYGON_API_KEY\": polygon_api_key}}\n",
    "else:\n",
    "    market_mcp = ({\"command\": \"uv\", \"args\": [\"run\", \"market_server.py\"]})\n",
    "\n",
    "trader_mcp_server_params = [\n",
    "    {\"command\": \"uv\", \"args\": [\"run\", \"accounts_server.py\"]},\n",
    "    {\"command\": \"uv\", \"args\": [\"run\", \"push_server.py\"]},\n",
    "    market_mcp\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "931d1164",
   "metadata": {},
   "source": [
    "### Researcher, Trader and Evaluator MCP Servers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8685d1ee",
   "metadata": {},
   "outputs": [],
   "source": [
    "brave_env = {\"BRAVE_API_KEY\": os.getenv(\"BRAVE_API_KEY\")}\n",
    "\n",
    "researcher_mcp_server_params = [\n",
    "    {\"command\": \"uvx\", \"args\": [\"mcp-server-fetch\"]},\n",
    "    {\"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-brave-search\"], \"env\": brave_env}\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "954845b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "evaluator_server_path = Path.cwd() / \"community_contributions\" / \"kwabena\" / \"evaluator_server.py\"\n",
    "\n",
    "evaluator_mcp_server_params = [\n",
    "    {\"command\": \"uv\", \"args\": [\"run\", str(evaluator_server_path)]}\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a5d4a2e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "researcher_mcp_servers = [MCPServerStdio(params, client_session_timeout_seconds=30) for params in researcher_mcp_server_params]\n",
    "trader_mcp_servers = [MCPServerStdio(params, client_session_timeout_seconds=30) for params in trader_mcp_server_params]\n",
    "evaluator_mcp_servers = [MCPServerStdio(params, client_session_timeout_seconds=30) for params in evaluator_mcp_server_params]\n",
    "mcp_servers = trader_mcp_servers + researcher_mcp_servers + evaluator_mcp_servers"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19aac28d",
   "metadata": {},
   "source": [
    "## Researcher Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4116f0a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "async def get_researcher(mcp_servers) -> Agent:\n",
    "    instructions = f\"\"\"You are a financial researcher. You are able to search the web for interesting financial news,\n",
    "                    look for possible trading opportunities, and help with research.\n",
    "                    Based on the request, you carry out necessary research and respond with your findings.\n",
    "                    Take time to make multiple searches to get a comprehensive overview, and then summarize your findings.\n",
    "                    If there isn't a specific request, then just respond with investment opportunities based on searching latest news.\n",
    "                    The current datetime is {datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")}\n",
    "                    \"\"\"\n",
    "    researcher = Agent(\n",
    "        name=\"Researcher\",\n",
    "        instructions=instructions,\n",
    "        model=\"gpt-4.1-mini\",\n",
    "        mcp_servers=mcp_servers,\n",
    "    )\n",
    "    return researcher"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6a38e20",
   "metadata": {},
   "outputs": [],
   "source": [
    "async def get_researcher_tool(mcp_servers) -> Tool:\n",
    "    researcher = await get_researcher(mcp_servers)\n",
    "    return researcher.as_tool(\n",
    "            tool_name=\"Researcher\",\n",
    "            tool_description=\"This tool researches online for news and opportunities, \\\n",
    "                either based on your specific request to look into a certain stock, \\\n",
    "                or generally for notable financial news and opportunities. \\\n",
    "                Describe what kind of research you're looking for.\"\n",
    "        )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7d238c19",
   "metadata": {},
   "outputs": [],
   "source": [
    "research_question = \"What's the latest news on Amazon?\"\n",
    "\n",
    "for server in researcher_mcp_servers:\n",
    "    await server.connect()\n",
    "researcher = await get_researcher(researcher_mcp_servers)\n",
    "with trace(\"Researcher\"):\n",
    "    result = await Runner.run(researcher, research_question, max_turns=30)\n",
    "display(Markdown(result.final_output))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "46d9a049",
   "metadata": {},
   "outputs": [],
   "source": [
    "project_root = Path.cwd().parent.parent\n",
    "os.chdir(project_root)\n",
    "sys.path.insert(0, str(project_root))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7022d833",
   "metadata": {},
   "outputs": [],
   "source": [
    "ed_initial_strategy = \"You are a day trader that aggressively buys and sells shares based on news and market conditions.\"\n",
    "Account.get(\"Ed\").reset(ed_initial_strategy)\n",
    "\n",
    "display(Markdown(await read_accounts_resource(\"Ed\")))\n",
    "display(Markdown(await read_strategy_resource(\"Ed\")))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13f71177",
   "metadata": {},
   "source": [
    "## Trader Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b121b0d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_name = \"Ed\"\n",
    "\n",
    "# Using MCP Servers to read resources\n",
    "account_details = await read_accounts_resource(agent_name)\n",
    "strategy = await read_strategy_resource(agent_name)\n",
    "\n",
    "instructions = f\"\"\"\n",
    "You are a trader that manages a portfolio of shares. Your name is {agent_name} and your account is under your name, {agent_name}.\n",
    "You have access to tools that allow you to search the internet for company news, check stock prices, and buy and sell shares.\n",
    "Your investment strategy for your portfolio is:\n",
    "{strategy}\n",
    "Your current holdings and balance is:\n",
    "{account_details}\n",
    "You have the tools to perform a websearch for relevant news and information.\n",
    "You have tools to check stock prices.\n",
    "You have tools to buy and sell shares.\n",
    "You have tools to save memory of companies, research and thinking so far.\n",
    "Please make use of these tools to manage your portfolio. Carry out trades as you see fit; do not wait for instructions or ask for confirmation.\n",
    "\"\"\"\n",
    "\n",
    "prompt = \"\"\"\n",
    "Use your tools to make decisions about your portfolio.\n",
    "Investigate the news and the market, make your decision, make the trades, and respond with a summary of your actions.\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c32ee6fb",
   "metadata": {},
   "outputs": [],
   "source": [
    "for server in mcp_servers:\n",
    "    await server.connect()\n",
    "\n",
    "researcher_tool = await get_researcher_tool(researcher_mcp_servers)\n",
    "trader = Agent(\n",
    "    name=agent_name,\n",
    "    instructions=instructions,\n",
    "    tools=[researcher_tool],\n",
    "    mcp_servers=trader_mcp_servers,\n",
    "    model=\"gpt-4o-mini\",\n",
    ")\n",
    "with trace(agent_name):\n",
    "    result = await Runner.run(trader, prompt, max_turns=30)\n",
    "display(Markdown(result.final_output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59f15cab",
   "metadata": {},
   "source": [
    "### Evaluator Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f10170e",
   "metadata": {},
   "outputs": [],
   "source": [
    "async def get_evaluator(evaluator_servers, trader_name: str) -> Agent:\n",
    "    \"\"\"Creates a simple evaluator agent\"\"\"\n",
    "    \n",
    "    strategy = await read_strategy_resource(trader_name)\n",
    "    \n",
    "    instructions = f\"\"\"You evaluate {trader_name}'s trading performance.\n",
    "\n",
    "Strategy: {strategy}\n",
    "\n",
    "You have ONE tool: evaluate_performance - gives all key metrics.\n",
    "\n",
    "Call it once, then provide:\n",
    "- Brief performance summary\n",
    "- 2-3 quick recommendations\n",
    "\"\"\"\n",
    "    \n",
    "    evaluator = Agent(\n",
    "        name=\"Evaluator\",\n",
    "        instructions=instructions,\n",
    "        model=\"gpt-4o-mini\",\n",
    "        mcp_servers=evaluator_servers,\n",
    "    )\n",
    "    return evaluator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fbcfa29b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Connect evaluator servers\n",
    "for server in evaluator_mcp_servers:\n",
    "    await server.connect()\n",
    "\n",
    "# Create and run evaluator\n",
    "evaluator = await get_evaluator(evaluator_mcp_servers, agent_name)\n",
    "\n",
    "with trace(\"Evaluator\"):\n",
    "    eval_result = await Runner.run(evaluator, \"Evaluate the trader's performance.\", max_turns=4)\n",
    "\n",
    "display(Markdown(\"## Performance Evaluation\"))\n",
    "display(Markdown(eval_result.final_output))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
